﻿#define _CRT_SECURE_NO_WARNINGS 1
//2024-1-22 Monday 12:35:18
//第13讲：深⼊理解指针(3) 
//⽬录 
//1. 字符指针变量
//2. 数组指针变量
//3. ⼆维数组传参的本质
//4. 函数指针变量
//5. 函数指针数组
//6. 转移表

//5. 函数指针数组
//4.3 两段有趣的代码
//int main()
//{
//	 void (*signal(int, void(*)(int)))(int);
//	 //void (*)(int) signal(int, void(*)(int));//err
//	 //*signal不是(*signal)，所以:不是函数指针，根据下文：也不是函数调用
//	 //(int, void(*)(int))，结尾带;所以:是函数声明
//	 //void(*)(int)函数的返回类型
//	 //上面的代码是一次函数声明 
//
//	 //结论：void(*函数)(int);函数声明
//
//	 return 0;
//}


//4.3.1 typedef关键字
//typedef unsigned int uint;
//typedef int* prt_t;
//
//typedef void(*pf_t)(int);//将函数指针重命名，新名字放在(*)里面
//
////pf_t p1;
////void (*p2)(int);
//
////int* p;
////prt_t p2;
//
//uint a = 0;
//unsigned int b = 0;
//
//void (*signal(int, void(*)(int)))(int);
//prt_t signal(int, prt_t);


//typedef int(*parr_t)[10];
//
//int main()
//{
//	int arr[10];
//	int(*parr)[10] = &arr;
//	parr_t parr2 = &arr;
//
//	return 0;
//}


//2024-1-23 Tuesday 12:58:00
//第13讲：深⼊理解指针(3) 
//⽬录 
//1. 字符指针变量
//2. 数组指针变量
//3. ⼆维数组传参的本质
//4. 函数指针变量
//5. 函数指针数组
//6. 转移表

//5. 函数指针数组
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int main()
//{
//	int* arr[10];//整型指针数组
//
//	//函数指针
//	int(*p1)(int, int) = Add;
//	int(*p2)(int, int) = Sub;
//
//	//函数指针数组 - 存放函数指针的数组
//	int(*parr[])(int, int) = { Add, Sub };
//
//	return 0;
//}


//第13讲：深⼊理解指针(3) 
//⽬录 
//1. 字符指针变量
//2. 数组指针变量
//3. ⼆维数组传参的本质
//4. 函数指针变量
//5. 函数指针数组
//6. 转移表

//6. 转移表
//计算器的⼀般实现
//#include <stdio.h>
//#pragma warning(disable : 4996)
//
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int Mul(int x, int y)
//{
//	return x * y;
//}
//
//int Div(int x, int y)
//{
//	return x / y;
//}
//
//void menu()
//{
//	printf("**************************\n");
//	printf("***** 1. add  2. sub *****\n");
//	printf("***** 3. mul  4. div *****\n");
//	printf("***** 0. exit        *****\n");
//	printf("**************************\n");
//}
//
//int main()
//{
//	int input = 0;
//	int n1 = 0;
//	int n2 = 0;
//	int ret = 0;
//
//	do
//	{
//		menu();
//		printf("请选择:> ");
//		scanf("%d", &input);
//
//		switch (input)
//		{
//		case 1:
//			printf("请输入两个操作数:> ");
//			scanf("%d %d", &n1, &n2);
//			ret = Add(n1, n2);
//			printf("%d\n", ret);
//			break;
//		case 2:
//			printf("请输入两个操作数:> ");
//			scanf("%d %d", &n1, &n2);
//			ret = Sub(n1, n2);
//			printf("%d\n", ret);
//			break;
//		case 3:
//			printf("请输入两个操作数:> ");
//			scanf("%d %d", &n1, &n2);
//			ret = Mul(n1, n2);
//			printf("%d\n", ret);
//			break;
//		case 4:
//			printf("请输入两个操作数:> ");
//			scanf("%d %d", &n1, &n2);
//			ret = Div(n1, n2);
//			printf("%d\n", ret);
//			break;
//		case 0:
//			printf("退出计算器\n");
//			break;
//		default:
//			printf("非法选择，请重新选择！\n");
//			break;
//		}
//
//	} while (input);
//	
//	return 0;
//}


//#include <stdio.h>
//#pragma warning(disable : 4996)
//
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int Mul(int x, int y)
//{
//	return x * y;
//}
//
//int Div(int x, int y)
//{
//	return x / y;
//}
//
//void menu()
//{
//	printf("**************************\n");
//	printf("***** 1. add  2. sub *****\n");
//	printf("***** 3. mul  4. div *****\n");
//	printf("***** 0. exit        *****\n");
//	printf("**************************\n");
//}
//
//int main()
//{
//	int(*pfArr[])(int, int) = { 0, Add, Sub, Mul, Div };
//	int input = 0;
//	int n1 = 0;
//	int n2 = 0;
//	int ret = 0;
//
//	do
//	{
//		menu();
//		printf("请选择:> ");
//		scanf("%d", &input);
//
//		if (input >= 1 && input <= 4)
//		{
//			printf("请输入两个操作数:> ");
//			scanf("%d %d", &n1, &n2);
//			//ret = pfArr[input](n1, n2);
			//ret = *pfArr[input](n1, n2);
//			ret = (*(pfArr + input))(n1, n2);
//			//ret = (pfArr + input)(n1, n2);//error???
//
//			printf("%d\n", ret);
//		}
//		else if (0 == input)
//		{
//			printf("退出计算器\n");
//		}
//		else
//		{
//			printf("非法选择，请重新选择！\n");
//		}
//
//	} while (input);
//
//	return 0;
//}


//2024-1-27 Saturday 21:07:54
//第14讲：深⼊理解指针(4)
//⽬录
//1. 回调函数是什么
//2. qsort使⽤举例
//3. qsort函数的模拟实现

//1. 回调函数是什么
//计算器 - 使用回调函数前
//#include <stdio.h>
//#include <limits.h>
//
//void menu()
//{
//	printf("**************************\n");
//	printf("***** 1. add  2. sub *****\n");
//	printf("***** 3. mul  4. div *****\n");
//	printf("***** 0. exit        *****\n");
//	printf("**************************\n");
//}
//
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int Mul(int x, int y)
//{
//	return x * y;
//}
//
//int Div(int x, int y)
//{
//	return x / y;
//}
//
//int main()
//{
//	int input = 0;
//	int a = 0;
//	int b = 0;
//	int ret = 0;
//
//	do
//	{
//		menu();
//		printf("请选择:> ");
//		scanf("%d", &input);
//
//		switch (input)
//		{
//		case 1:
//			printf("麻烦请输入两个整数！（输入的值不大于%d）\n", INT_MAX);
//			printf("第 1 个整数： ");
//			scanf("%d", &a);
//			printf("第 2 个整数： ");
//			scanf("%d", &b);
//			ret = Add(a, b);
//			printf("%d\n", ret);
//			break;
//		case 2:
//			printf("麻烦请输入两个整数！（输入的值不大于%d）\n", INT_MAX);
//			printf("第 1 个整数： ");
//			scanf("%d", &a);
//			printf("第 2 个整数： ");
//			scanf("%d", &b);
//			ret = Sub(a, b);
//			printf("%d\n", ret);
//			break;
//		case 3:
//			printf("麻烦请输入两个整数！（输入的值不大于%d）\n", INT_MAX);
//			printf("第 1 个整数： ");
//			scanf("%d", &a);
//			printf("第 2 个整数： ");
//			scanf("%d", &b);
//			ret = Mul(a, b);
//			printf("%d\n", ret);
//			break;
//		case 4:
//			printf("麻烦请输入两个整数！（输入的值不大于%d）\n", INT_MAX);
//			printf("第 1 个整数： ");
//			scanf("%d", &a);
//			printf("第 2 个整数： ");
//			scanf("%d", &b);
//			ret = Div(a, b);
//			printf("%d\n", ret);
//			break;
//		case 0:
//			printf("您已成功退出计算器！\n");
//			break;
//		default:
//			printf("选择错误，重新选择！\n");
//			break;
//		}
//
//	} while (input);
//
//	return 0;
//}


//转移表
//局限性：必须具有相同类型的函数指针...
//#include <stdio.h>
//#include <limits.h>
//
//void menu()
//{
//	printf("**************************\n");
//	printf("***** 1. add  2. sub *****\n");
//	printf("***** 3. mul  4. div *****\n");
//	printf("***** 0. exit        *****\n");
//	printf("**************************\n");
//}
//
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int Mul(int x, int y)
//{
//	return x * y;
//}
//
//int Div(int x, int y)
//{
//	return x / y;
//}
//
//int main()
//{
//	int(*parr[10])(int, int) = { 0, Add, Sub, Mul, Div };
//	int input = 0;
//	int a = 0;
//	int b = 0;
//	int ret = 0;
//
//	do
//	{
//		menu();
//		printf("请选择:> ");
//		scanf("%d", &input);
//
//		if (input >= 1 && input <= 4)
//		{
//			printf("麻烦请输入两个整数！（输入的值不大于%d）\n", INT_MAX);
//			printf("第 1 个整数： ");
//			scanf("%d", &a);
//			printf("第 2 个整数： ");
//			scanf("%d", &b);
//			ret = parr[input](a, b);//通过函数指针调用的函数，那个函数就是回调函数
//			//ret = (parr + input)(a, b);//为什么不能调，parr + input不是指针吗？指针就是函数名啊？不是可以调吗？
//			ret = (*(parr + input))(a, b);
//			printf("\n他们的结果是：%d  ------------------\n", ret);
//		}
//		else if (0 == input)
//		{
//			printf("您已成功退出计算器！\n");
//		}
//		else
//		{
//			printf("选择错误，重新选择！\n");
//		}
//
//	} while (input);
//
//	return 0;
//}


//使用回调函数后
//#include <stdio.h>
//#include <limits.h>
//
//void menu()
//{
//	printf("**************************\n");
//	printf("***** 1. add  2. sub *****\n");
//	printf("***** 3. mul  4. div *****\n");
//	printf("***** 0. exit        *****\n");
//	printf("**************************\n");
//}
//
//int Add(int x, int y)
//{
//	return x + y;
//}
//
//int Sub(int x, int y)
//{
//	return x - y;
//}
//
//int Mul(int x, int y)
//{
//	return x * y;
//}
//
//int Div(int x, int y)
//{
//	return x / y;
//}
//
//void calc(int(*pf)(int, int))
//{
//	int a = 0;
//	int b = 0;
//	int ret = 0;
//
//	printf("麻烦请输入两个整数！（输入的值不大于%d）\n", INT_MAX);
//	printf("第 1 个整数： ");
//	scanf("%d", &a);
//	printf("第 2 个整数： ");
//	scanf("%d", &b);
//	ret = pf(a, b);//通过函数指针调用的函数，那个函数就是回调函数
//	printf("\n他们的结果是：%d  ------------------\n", ret);
//}
//
//int main()
//{
//	int input = 0;
//
//	do
//	{
//		menu();
//		printf("请选择:> ");
//		scanf("%d", &input);
//
//		switch (input)
//		{
//		case 1:
//			calc(Add);
//			break;
//		case 2:
//			calc(Sub);
//			break;
//		case 3:
//			calc(Mul);
//			break;
//		case 4:
//			calc(Div);
//			break;
//		case 0:
//			printf("您已成功退出计算器！\n");
//			break;
//		default:
//			printf("选择错误，重新选择！\n");
//			break;
//		}
//
//	} while (input);
//
//	return 0;
//}


//2024-1-28 Sunday 16:22:10
//第14讲：深⼊理解指针(4)
//⽬录
//1. 回调函数是什么
//2. qsort使⽤举例
//3. qsort函数的模拟实现
 
//2. qsort使⽤举例
//void qsort(void* base, //base指向待排序的第一个元素（My understanding:谁指向谁就是地址）
//	         size_t num, //待排序的元素个数
//		     size_t size, //待排序的数组的元素的大小，单位是字节(byte)
//	         int(*compar)(const void*, const void*) //compar是一个函数指针，指向的函数能够比较2个元素
//	                                              //My understanding:compar是指针变量名，可以随便取
//          )

//qsort函数有4个参数

//void* 是什么？
//是一种指针类型

//int main()
//{
//	int a = 10;
//	int* p = &a;
//	char* pc = &a;//int* ----> char*
//
//	void* pv = &a;//int* ----> void*
//	//无具体类型的指针，通用指针类型
//	//void*类型的指针变量，可以接受任意类型数据的地址
//	//My understanding:但不能进行计算，因为无具体类型，所以不知道跳过几个字节
//	/**pv + 1
//	*pv*/
//
//	return 0;
//}

//程序员A
//void qsort(void* base, //base指向待排序的第一个元素
//          size_t num,  //待排序的元素个数
//          size_t size, //待排序的数组元素的大小，单位是字节
//          int (*compar)(const void* e1, const void* e2) //compar是一个函数指针，指向的函数能够比较2个元素
//          );
//qsort函数使用的是[快速排序]的思想排序数据的
//排序的算法很多：
//冒泡排序，选择排序，插入排序，希尔排序，快速排序...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//这个函数能够比较e1和e2指向的两个元素，并且给出返回值
//int cmp_int(const void* e1, const void* e2)
//{
 ////详写：if (*(int*)e1 > *(int*)e2)
 //{
	//	return 1;
 //}
 //else if (*(int*)e1 == *(int*)e2)
 //{
 //return 0;
 //}
 //else
 //{
 //return -1;
 //}
//	return *(int*)e1 - *(int*)e2;//My understanding:因为返回值是int，所以强转，库函数有用法示例
//}
//
//void print_arr(int* parr, int sz)
//{
//	int i = 0;
//
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *(parr + i));
//	}
//	printf("\n");
//}
//
////test1测试qsort排序整型数组
//int main()
//{
//	int arr[] = { 3, 1, 5, 7, 2, 4, 8, 6, 0, 9 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	print_arr(arr, sz);
//	qsort(arr, sz, sizeof(arr[0]), cmp_int);
//	print_arr(arr, sz);
//
//	return 0;
//}


//test2测试qsort函数排序结构体数据
//struct Stu //学生
//{
//	char name[20]; //名字
//	int age; //年龄
//};
//
////假设按照年龄来比较
//int cmp_stu_by_age(const void* e1, const void* e2)
//{
//	return  ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
//}
//
////假设按照名字来比较
//int cmp_stu_by_name(const void* e1, const void* e2)
//{
//	//strcmp - 是库函数，是专门用来比较两个字符串的大小的
//	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
//}
//
//void print_s(struct Stu* s, int sz)
//{
//	int i = 0;
//	
//	for (i = 0; i < sz; i++)
//	{
//		//printf("%s %d ", (s + i)->name, (s + i)->age);
//		//or
//		printf("%s %d ", s[i].name, s[i].age);
//	}
//	printf("\n");
//}
//
//void test2()
//{
//struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
//	int sz = sizeof(s) / sizeof(s[0]);
//	//qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
//	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
//	print_s(s, sz);
//}
//
//int main()
//{
//	test2();
//
//	return 0;
//}


//2024-1-29 Monthday 18:45:07
//冒泡排序的思想
//只能排序整型数据
//拓展：能不能让sort函数可以排序任意类型数据呢？
//#include <stdio.h>
//
//void print_arr(int* arr, int sz)
//{
//	int i = 0;
//
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *(arr + i));
//	}
//	printf("\n");
//}
//
//void sort(int* arr, int sz)
//{
//	int i = 0;
//
//	for (i = 0; i < sz - 1; i++)
//	{
//		int flag = 1;//假设不用排
//		int j = 0;
//
//		for (j = 0; j < sz - 1 - i; j++)
//		{
//			//一趟冒泡排序
//			if (arr[j] > arr[j + 1])//升序，降序就倒过来
//			{
//				int tmp = arr[j];
//				arr[j] = arr[j + 1];
//				arr[j + 1] = tmp;
//				flag = 0;//这一趟进来，交换了一次说明要排，就让这趟排下去
//			}
//		}
//		if (1 == flag)//如果一趟不用排，说明就整个不用排了，直接跳出整个循环
//		{
//			break;
//		}
//	}
//}
//
//int main()
//{
//	int arr[] = { 3, 1, 5, 7, 2, 4, 8, 6, 0, 9 };
//	//            0  1
//	//				 1  2  
//	//10 - 9
//	//9  - 8
//	//8  - 7
//
//	int sz = sizeof(arr) / sizeof(arr[0]);
//
//	sort(arr, sz);
//	print_arr(arr, sz);
//
//	return 0;
//}


//My understanding:
//自主实现扩展
//哎想不出来啊
#include <stdio.h>

void print_arr(int* arr, int sz)
{
	int i = 0;

	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(arr + i));
	}
	printf("\n");
}

void sort(void* base, size_t sum, size_t size, int(*compar)(const void* a, const void* b))
{
	int i = 0;

	for (i = 0; i < sum - 1; i++)
	{
		int flag = 1;
		int j = 0;

		for (j = 0; j < sum - 1 - i; j++)
		{
			if (1 == compar)
			{
				compar(base[j], base[j + 1]);
				int tmp = base[j];
				base[j] = base[j + 1];
				base[j + 1] = tmp;
				flag = 0;
			}
		}
		if (1 == flag)
		{
			break;
		}
	}
}

int compar_int(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;
}

int main()
{
	int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	
	sort(arr, sz, sizeof(arr[0]), compar_int);
	print_arr(arr, sz);

	return 0;
}

//int float

//结构体类型
//struct Stu
//{
//	char name[20]; //名字
//	int age; //年龄
//};
//
//int main()
//{
//	int a = 0;
//	struct Stu s = { "zhangsan", 20 };
//	printf("%s %d\n", s.name, s.age); //结构成员访问操作符：	结构体变量. 成员名
//
//	struct Stu* ps = &s;
//	printf("%s %d\n", (*ps).name, (*ps).age);
//	printf("%s %d\n", ps->name, ps->age); //结构成员访问操作符：	结构体指针->成员名
//
//	return 0;
//}